home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows (5th Edition) / Programming Windows, 5th ed. - Companion CD (097-0002183)(1999).iso / Chap19 / MDIDemo / MDIDemo.c next >
Encoding:
C/C++ Source or Header  |  1998-10-09  |  17.6 KB  |  497 lines

  1. /*--------------------------------------------------------
  2.    MDIDEMO.C -- Multiple-Document Interface Demonstration
  3.                 (c) Charles Petzold, 1998
  4.   --------------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include "resource.h"
  8.  
  9. #define INIT_MENU_POS    0
  10. #define HELLO_MENU_POS   2
  11. #define RECT_MENU_POS    1
  12.  
  13. #define IDM_FIRSTCHILD   50000
  14.  
  15. LRESULT CALLBACK FrameWndProc  (HWND, UINT, WPARAM, LPARAM) ;
  16. BOOL    CALLBACK CloseEnumProc (HWND, LPARAM) ;
  17. LRESULT CALLBACK HelloWndProc  (HWND, UINT, WPARAM, LPARAM) ;
  18. LRESULT CALLBACK RectWndProc   (HWND, UINT, WPARAM, LPARAM) ;
  19.  
  20.      // structure for storing data unique to each Hello child window
  21.  
  22. typedef struct tagHELLODATA
  23. {
  24.      UINT     iColor ;
  25.      COLORREF clrText ;
  26. }
  27. HELLODATA, * PHELLODATA ;
  28.  
  29.      // structure for storing data unique to each Rect child window
  30.  
  31. typedef struct tagRECTDATA
  32. {
  33.      short cxClient ;
  34.      short cyClient ;
  35. }
  36. RECTDATA, * PRECTDATA ;
  37.  
  38.      // global variables
  39.  
  40. TCHAR     szAppName[]    = TEXT ("MDIDemo") ;
  41. TCHAR     szFrameClass[] = TEXT ("MdiFrame") ;
  42. TCHAR     szHelloClass[] = TEXT ("MdiHelloChild") ;
  43. TCHAR     szRectClass[]  = TEXT ("MdiRectChild") ;
  44. HINSTANCE hInst ;
  45. HMENU     hMenuInit, hMenuHello, hMenuRect ;
  46. HMENU     hMenuInitWindow, hMenuHelloWindow, hMenuRectWindow ;
  47.  
  48. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  49.                     PSTR szCmdLine, int iCmdShow)
  50. {
  51.      HACCEL   hAccel ;
  52.      HWND     hwndFrame, hwndClient ;
  53.      MSG      msg ;
  54.      WNDCLASS wndclass ;
  55.      
  56.      hInst = hInstance ;
  57.      
  58.           // Register the frame window class
  59.           
  60.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  61.      wndclass.lpfnWndProc   = FrameWndProc ;
  62.      wndclass.cbClsExtra    = 0 ;
  63.      wndclass.cbWndExtra    = 0 ;
  64.      wndclass.hInstance     = hInstance ;
  65.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  66.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  67.      wndclass.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1) ;
  68.      wndclass.lpszMenuName  = NULL ;
  69.      wndclass.lpszClassName = szFrameClass ;
  70.      
  71.      if (!RegisterClass (&wndclass))
  72.      {
  73.           MessageBox (NULL, TEXT ("This program requires Windows NT!"),
  74.                       szAppName, MB_ICONERROR) ;
  75.           return 0 ;
  76.      }
  77.         
  78.           // Register the Hello child window class
  79.           
  80.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  81.      wndclass.lpfnWndProc   = HelloWndProc ;
  82.      wndclass.cbClsExtra    = 0 ;
  83.      wndclass.cbWndExtra    = sizeof (HANDLE) ;
  84.      wndclass.hInstance     = hInstance ;
  85.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  86.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  87.      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  88.      wndclass.lpszMenuName  = NULL ;
  89.      wndclass.lpszClassName = szHelloClass ;
  90.           
  91.      RegisterClass (&wndclass) ;
  92.           
  93.           // Register the Rect child window class
  94.           
  95.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  96.      wndclass.lpfnWndProc   = RectWndProc ;
  97.      wndclass.cbClsExtra    = 0 ;
  98.      wndclass.cbWndExtra    = sizeof (HANDLE) ;
  99.      wndclass.hInstance     = hInstance ;
  100.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  101.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  102.      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  103.      wndclass.lpszMenuName  = NULL ;
  104.      wndclass.lpszClassName = szRectClass ;
  105.           
  106.      RegisterClass (&wndclass) ;
  107.  
  108.           // Obtain handles to three possible menus & submenus
  109.      
  110.      hMenuInit  = LoadMenu (hInstance, TEXT ("MdiMenuInit")) ;
  111.      hMenuHello = LoadMenu (hInstance, TEXT ("MdiMenuHello")) ;
  112.      hMenuRect  = LoadMenu (hInstance, TEXT ("MdiMenuRect")) ;
  113.      
  114.      hMenuInitWindow  = GetSubMenu (hMenuInit,   INIT_MENU_POS) ;
  115.      hMenuHelloWindow = GetSubMenu (hMenuHello, HELLO_MENU_POS) ;
  116.      hMenuRectWindow  = GetSubMenu (hMenuRect,   RECT_MENU_POS) ;
  117.      
  118.           // Load accelerator table
  119.      
  120.      hAccel = LoadAccelerators (hInstance, szAppName) ;
  121.  
  122.           // Create the frame window
  123.      
  124.      hwndFrame = CreateWindow (szFrameClass, TEXT ("MDI Demonstration"),
  125.                                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  126.                                CW_USEDEFAULT, CW_USEDEFAULT,
  127.                                CW_USEDEFAULT, CW_USEDEFAULT,
  128.                                NULL, hMenuInit, hInstance, NULL) ;
  129.      
  130.      hwndClient = GetWindow (hwndFrame, GW_CHILD) ;
  131.      
  132.      ShowWindow (hwndFrame, iCmdShow) ;
  133.      UpdateWindow (hwndFrame) ;
  134.      
  135.           // Enter the modified message loop
  136.      
  137.      while (GetMessage (&msg, NULL, 0, 0))
  138.      {
  139.           if (!TranslateMDISysAccel (hwndClient, &msg) &&
  140.               !TranslateAccelerator (hwndFrame, hAccel, &msg))
  141.           {
  142.                TranslateMessage (&msg) ;
  143.                DispatchMessage (&msg) ;
  144.           }
  145.      }
  146.           // Clean up by deleting unattached menus
  147.      
  148.      DestroyMenu (hMenuHello) ;
  149.      DestroyMenu (hMenuRect) ;
  150.      
  151.      return msg.wParam ;
  152.      }
  153.      
  154. LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT message, 
  155.                                WPARAM wParam, LPARAM lParam)
  156. {
  157.      static HWND        hwndClient ;
  158.      CLIENTCREATESTRUCT clientcreate ;
  159.      HWND               hwndChild ;
  160.      MDICREATESTRUCT    mdicreate ;
  161.           
  162.      switch (message)
  163.      {
  164.      case WM_CREATE:           // Create the client window
  165.           
  166.           clientcreate.hWindowMenu  = hMenuInitWindow ;
  167.           clientcreate.idFirstChild = IDM_FIRSTCHILD ;
  168.           
  169.           hwndClient = CreateWindow (TEXT ("MDICLIENT"), NULL,
  170.                                      WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,   
  171.                                      0, 0, 0, 0, hwnd, (HMENU) 1, hInst,
  172.                                      (PSTR) &clientcreate) ;
  173.           return 0 ;
  174.           
  175.      case WM_COMMAND:
  176.           switch (LOWORD (wParam))
  177.           {
  178.           case IDM_FILE_NEWHELLO:       // Create a Hello child window
  179.                
  180.                mdicreate.szClass = szHelloClass ;
  181.                mdicreate.szTitle = TEXT ("Hello") ;
  182.                mdicreate.hOwner  = hInst ;
  183.                mdicreate.x       = CW_USEDEFAULT ;
  184.                mdicreate.y       = CW_USEDEFAULT ;
  185.                mdicreate.cx      = CW_USEDEFAULT ;
  186.                mdicreate.cy      = CW_USEDEFAULT ;
  187.                mdicreate.style   = 0 ;
  188.                mdicreate.lParam  = 0 ;
  189.                
  190.                hwndChild = (HWND) SendMessage (hwndClient,
  191.                                    WM_MDICREATE, 0,
  192.                                    (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ;
  193.                return 0 ;
  194.                
  195.           case IDM_FILE_NEWRECT:        // Create a Rect child window
  196.                
  197.                mdicreate.szClass = szRectClass ;
  198.                mdicreate.szTitle = TEXT ("Rectangles") ;
  199.                mdicreate.hOwner  = hInst ;
  200.                mdicreate.x       = CW_USEDEFAULT ;
  201.                mdicreate.y       = CW_USEDEFAULT ;
  202.                mdicreate.cx      = CW_USEDEFAULT ;
  203.                mdicreate.cy      = CW_USEDEFAULT ;
  204.                mdicreate.style   = 0 ;
  205.                mdicreate.lParam  = 0 ;
  206.                
  207.                hwndChild = (HWND) SendMessage (hwndClient,
  208.                                    WM_MDICREATE, 0,
  209.                                    (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ;
  210.                return 0 ;
  211.                
  212.           case IDM_FILE_CLOSE:          // Close the active window
  213.                
  214.                hwndChild = (HWND) SendMessage (hwndClient,
  215.                                                WM_MDIGETACTIVE, 0, 0) ;
  216.                
  217.                if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0))
  218.                     SendMessage (hwndClient, WM_MDIDESTROY,
  219.                                  (WPARAM) hwndChild, 0) ;
  220.                return 0 ;
  221.                
  222.           case IDM_APP_EXIT:            // Exit the program
  223.                
  224.                SendMessage (hwnd, WM_CLOSE, 0, 0) ;
  225.                return 0 ;
  226.                
  227.                // messages for arranging windows
  228.  
  229.           case IDM_WINDOW_TILE:
  230.                SendMessage (hwndClient, WM_MDITILE, 0, 0) ;
  231.                return 0 ;
  232.                
  233.           case IDM_WINDOW_CASCADE:
  234.                SendMessage (hwndClient, WM_MDICASCADE, 0, 0) ;
  235.                return 0 ;
  236.                
  237.           case IDM_WINDOW_ARRANGE:
  238.                SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0) ;
  239.                return 0 ;
  240.                
  241.           case IDM_WINDOW_CLOSEALL:     // Attempt to close all children
  242.                
  243.                EnumChildWindows (hwndClient, CloseEnumProc, 0) ;
  244.                return 0 ;
  245.                
  246.           default:             // Pass to active child...
  247.                
  248.                hwndChild = (HWND) SendMessage (hwndClient,
  249.                                                WM_MDIGETACTIVE, 0, 0) ;
  250.                
  251.                if (IsWindow (hwndChild))
  252.                     SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ;
  253.                
  254.                break ;        // ...and then to DefFrameProc
  255.           }
  256.           break ;
  257.           
  258.      case WM_QUERYENDSESSION:
  259.      case WM_CLOSE:                      // Attempt to close all children
  260.                
  261.           SendMessage (hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0) ;
  262.                
  263.           if (NULL != GetWindow (hwndClient, GW_CHILD))
  264.                return 0 ;
  265.                
  266.           break ;   // i.e., call DefFrameProc 
  267.                
  268.      case WM_DESTROY:
  269.           PostQuitMessage (0) ;
  270.           return 0 ;
  271.      }
  272.           // Pass unprocessed messages to DefFrameProc (not DefWindowProc)
  273.      
  274.      return DefFrameProc (hwnd, hwndClient, message, wParam, lParam) ;
  275. }
  276.  
  277. BOOL CALLBACK CloseEnumProc (HWND hwnd, LPARAM lParam)
  278. {
  279.      if (GetWindow (hwnd, GW_OWNER))         // Check for icon title
  280.           return TRUE ;
  281.      
  282.      SendMessage (GetParent (hwnd), WM_MDIRESTORE, (WPARAM) hwnd, 0) ;
  283.      
  284.      if (!SendMessage (hwnd, WM_QUERYENDSESSION, 0, 0))
  285.           return TRUE ;
  286.      
  287.      SendMessage (GetParent (hwnd), WM_MDIDESTROY, (WPARAM) hwnd, 0) ;
  288.      return TRUE ;
  289. }
  290.  
  291. LRESULT CALLBACK HelloWndProc (HWND hwnd, UINT message, 
  292.                                WPARAM wParam, LPARAM lParam)
  293. {
  294.      static COLORREF clrTextArray[] = { RGB (0,   0, 0), RGB (255, 0,   0),
  295.                                         RGB (0, 255, 0), RGB (  0, 0, 255),
  296.                                         RGB (255, 255, 255) } ;
  297.      static HWND     hwndClient, hwndFrame ;
  298.      HDC             hdc ;
  299.      HMENU           hMenu ;
  300.      PHELLODATA      pHelloData ;
  301.      PAINTSTRUCT     ps ;
  302.      RECT            rect ;
  303.      
  304.      switch (message)
  305.      {
  306.      case WM_CREATE:
  307.                // Allocate memory for window private data
  308.           
  309.           pHelloData = (PHELLODATA) HeapAlloc (GetProcessHeap (),
  310.                               HEAP_ZERO_MEMORY, sizeof (HELLODATA)) ;
  311.  
  312.           pHelloData->iColor  = IDM_COLOR_BLACK ;
  313.           pHelloData->clrText = RGB (0, 0, 0) ;
  314.           SetWindowLong (hwnd, 0, (long) pHelloData) ;
  315.           
  316.                // Save some window handles
  317.           
  318.           hwndClient = GetParent (hwnd) ;
  319.           hwndFrame  = GetParent (hwndClient) ;
  320.           return 0 ;
  321.           
  322.      case WM_COMMAND:
  323.           switch (LOWORD (wParam))
  324.           {
  325.           case IDM_COLOR_BLACK:
  326.           case IDM_COLOR_RED:
  327.           case IDM_COLOR_GREEN:
  328.           case IDM_COLOR_BLUE:
  329.           case IDM_COLOR_WHITE:
  330.                     // Change the text color
  331.                
  332.                pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ;
  333.                
  334.                hMenu = GetMenu (hwndFrame) ;
  335.                
  336.                CheckMenuItem (hMenu, pHelloData->iColor, MF_UNCHECKED) ;
  337.                pHelloData->iColor = wParam ;
  338.                CheckMenuItem (hMenu, pHelloData->iColor, MF_CHECKED) ;
  339.                
  340.                pHelloData->clrText = clrTextArray[wParam - IDM_COLOR_BLACK] ;
  341.                
  342.                InvalidateRect (hwnd, NULL, FALSE) ;
  343.           }
  344.           return 0 ;
  345.           
  346.      case WM_PAINT:
  347.                // Paint the window
  348.                
  349.           hdc = BeginPaint (hwnd, &ps) ;
  350.                
  351.           pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ;
  352.           SetTextColor (hdc, pHelloData->clrText) ;
  353.                
  354.           GetClientRect (hwnd, &rect) ;
  355.                
  356.           DrawText (hdc, TEXT ("Hello, World!"), -1, &rect,
  357.                     DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
  358.                
  359.           EndPaint (hwnd, &ps) ;
  360.           return 0 ;
  361.                
  362.      case WM_MDIACTIVATE:
  363.                // Set the Hello menu if gaining focus
  364.                
  365.           if (lParam == (LPARAM) hwnd)
  366.                SendMessage (hwndClient, WM_MDISETMENU,
  367.                             (WPARAM) hMenuHello, (LPARAM) hMenuHelloWindow) ;
  368.                
  369.                // Check or uncheck menu item
  370.                
  371.           pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ;
  372.           CheckMenuItem (hMenuHello, pHelloData->iColor,
  373.                     (lParam == (LPARAM) hwnd) ? MF_CHECKED : MF_UNCHECKED) ;
  374.                
  375.                // Set the Init menu if losing focus
  376.                
  377.           if (lParam != (LPARAM) hwnd)
  378.                SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,
  379.                             (LPARAM) hMenuInitWindow) ;
  380.                
  381.           DrawMenuBar (hwndFrame) ;
  382.           return 0 ;
  383.                
  384.      case WM_QUERYENDSESSION:
  385.      case WM_CLOSE:
  386.           if (IDOK != MessageBox (hwnd, TEXT ("OK to close window?"),
  387.                                   TEXT ("Hello"), 
  388.                                   MB_ICONQUESTION | MB_OKCANCEL))
  389.                return 0 ;
  390.                
  391.           break ;   // i.e., call DefMDIChildProc
  392.                
  393.      case WM_DESTROY:
  394.           pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ;
  395.           HeapFree (GetProcessHeap (), 0, pHelloData) ;
  396.           return 0 ;
  397.      }
  398.           // Pass unprocessed message to DefMDIChildProc
  399.      
  400.      return DefMDIChildProc (hwnd, message, wParam, lParam) ;
  401. }
  402.  
  403. LRESULT CALLBACK RectWndProc (HWND hwnd, UINT message, 
  404.                               WPARAM wParam, LPARAM lParam)
  405. {
  406.      static HWND hwndClient, hwndFrame ;
  407.      HBRUSH      hBrush ;
  408.      HDC         hdc ;
  409.      PRECTDATA   pRectData ;
  410.      PAINTSTRUCT ps ;
  411.      int         xLeft, xRight, yTop, yBottom ;
  412.      short       nRed, nGreen, nBlue ;
  413.      
  414.      switch (message)
  415.      {
  416.      case WM_CREATE:
  417.                // Allocate memory for window private data
  418.           
  419.           pRectData = (PRECTDATA) HeapAlloc (GetProcessHeap (),
  420.                                    HEAP_ZERO_MEMORY, sizeof (RECTDATA)) ;
  421.           
  422.           SetWindowLong (hwnd, 0, (long) pRectData) ;
  423.           
  424.                // Start the timer going
  425.           
  426.           SetTimer (hwnd, 1, 250, NULL) ;
  427.           
  428.                // Save some window handles
  429.           
  430.           hwndClient = GetParent (hwnd) ;
  431.           hwndFrame  = GetParent (hwndClient) ;
  432.           return 0 ;
  433.           
  434.      case WM_SIZE:             // If not minimized, save the window size
  435.           
  436.           if (wParam != SIZE_MINIMIZED)
  437.           {
  438.                pRectData = (PRECTDATA) GetWindowLong (hwnd, 0) ;
  439.                
  440.                pRectData->cxClient = LOWORD (lParam) ;
  441.                pRectData->cyClient = HIWORD (lParam) ;
  442.           }
  443.           
  444.           break ;        // WM_SIZE must be processed by DefMDIChildProc
  445.           
  446.      case WM_TIMER:            // Display a random rectangle
  447.           
  448.           pRectData = (PRECTDATA) GetWindowLong (hwnd, 0) ;
  449.           
  450.           xLeft   = rand () % pRectData->cxClient ;
  451.           xRight  = rand () % pRectData->cxClient ;
  452.           yTop    = rand () % pRectData->cyClient ;
  453.           yBottom = rand () % pRectData->cyClient ;
  454.           nRed    = rand () & 255 ;
  455.           nGreen  = rand () & 255 ;
  456.           nBlue   = rand () & 255 ;
  457.           
  458.           hdc = GetDC (hwnd) ;
  459.           hBrush = CreateSolidBrush (RGB (nRed, nGreen, nBlue)) ;
  460.           SelectObject (hdc, hBrush) ;
  461.           
  462.           Rectangle (hdc, min (xLeft, xRight), min (yTop, yBottom),
  463.                max (xLeft, xRight), max (yTop, yBottom)) ;
  464.           
  465.           ReleaseDC (hwnd, hdc) ;
  466.           DeleteObject (hBrush) ;
  467.           return 0 ;
  468.           
  469.      case WM_PAINT:            // Clear the window
  470.           
  471.           InvalidateRect (hwnd, NULL, TRUE) ;
  472.           hdc = BeginPaint (hwnd, &ps) ;
  473.           EndPaint (hwnd, &ps) ;
  474.           return 0 ;
  475.           
  476.      case WM_MDIACTIVATE:      // Set the appropriate menu
  477.           if (lParam == (LPARAM) hwnd)
  478.                SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuRect,
  479.                             (LPARAM) hMenuRectWindow) ;
  480.           else
  481.                SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,
  482.                             (LPARAM) hMenuInitWindow) ;
  483.           
  484.           DrawMenuBar (hwndFrame) ;
  485.           return 0 ;
  486.           
  487.      case WM_DESTROY:
  488.           pRectData = (PRECTDATA) GetWindowLong (hwnd, 0) ;
  489.           HeapFree (GetProcessHeap (), 0, pRectData) ;
  490.           KillTimer (hwnd, 1) ;
  491.           return 0 ;
  492.      }
  493.           // Pass unprocessed message to DefMDIChildProc
  494.      
  495.      return DefMDIChildProc (hwnd, message, wParam, lParam) ;
  496. }
  497.